package com.blood.core.config.interceptor;

import cn.hutool.json.JSONConfig;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONTokener;
import com.blood.core.annotation.Idempotent;
import com.blood.core.util.ObjectAssertUtil;
import com.blood.core.util.http.ReqDedUpHelper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.RequestBodyAdviceAdapter;

import javax.xml.bind.DatatypeConverter;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Type;

/**
 * 请求幂等性
 *
 * @author daoren
 */
@ControllerAdvice
@Configuration
public class IdempotentRequest extends RequestBodyAdviceAdapter {

    @Autowired
    private ReqDedUpHelper reqDedUpHelper;
    private JSONConfig jsonConfig = new JSONConfig();

    @Override
    public boolean supports(MethodParameter methodParameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
        return methodParameter.hasMethodAnnotation(Idempotent.class) || methodParameter.hasParameterAnnotation(Idempotent.class);
    }

    @Override
    public HttpInputMessage beforeBodyRead(final HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) throws IOException {
        JSONObject jsonObject = new JSONObject(new JSONTokener(inputMessage.getBody(), jsonConfig));
        final byte[] body = jsonObject.toString().getBytes();
        ObjectAssertUtil.isBoolean(reqDedUpHelper.checkInfo(((Class) targetType).getName().concat(parameter.getMethod().getName()), DatatypeConverter.printHexBinary(body)), "请勿重复操作!");
        return new HttpInputMessage() {
            @Override
            public InputStream getBody() {
                return new ByteArrayInputStream(body);
            }

            @Override
            public HttpHeaders getHeaders() {
                return inputMessage.getHeaders();
            }
        };

    }
}
